﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.MicroKernel.Registration;
using System.ComponentModel.Composition;
using Castle.Windsor;
using Castle.MicroKernel.SubSystems.Configuration;
using Topics.Radical.ComponentModel.Messaging;
using Topics.Radical;
using Topics.Radical.Reflection;
using Castle.Core;
using Topics.Radical.ComponentModel;
using Topics.Radical.Threading;
using Topics.Radical.Messaging;
using Topics.Radical.Bootstrapper;
using Topics.Radical.ComponentModel.Validation;

namespace Topics.Radical.Bootstrapper.Installers
{
    /// <summary>
    /// Default boot installer.
    /// </summary>
    [Export( typeof( IWindsorInstaller ) )]
    public sealed class DefaultInstaller : IWindsorInstaller
    {
        /// <summary>
        /// Performs the installation in the <see cref="T:Castle.Windsor.IWindsorContainer"/>.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="store">The configuration store.</param>
        public void Install( IWindsorContainer container, IConfigurationStore store )
        {
            var boot = container.Resolve<IBootstrapper>();
            var directory = boot.ProbeDirectory;
			var filter = boot.AssemblyFilter;

            container.Register
            (
                Component.For<IWindsorContainer>()
                    .Instance( container )
            );

			container.Register
			(
				Types.FromAssemblyInDirectory( new AssemblyFilter( directory, filter ) )
					.IncludeNonPublicTypes()
					.Where( t => !t.IsInterface && !t.IsAbstract && !String.IsNullOrWhiteSpace( t.Namespace ) && t.Namespace.EndsWith( ".Services" ) )
					.WithService.FirstInterface()
					.Configure( c =>
					{
						if ( c.Implementation.Is<IRequireToStart>() )
						{
							c.Forward<IRequireToStart>();
						}
					} )
			);

			container.Register
			(
				Types.FromAssemblyInDirectory( new AssemblyFilter( directory, filter ) )
					.Where( t => !t.IsInterface && !t.IsAbstract && t.IsNested && t.Name.EndsWith( "Factory" ) )
					.WithService.Self()
					.LifestyleSingleton()
			);

			container.Register
			(
				Types.FromAssemblyInDirectory( new AssemblyFilter( directory, filter ) )
					.Where( t => !t.IsInterface && !t.IsAbstract && !String.IsNullOrWhiteSpace( t.Namespace ) && t.Namespace.EndsWith( ".Validators" ) && t.Is( typeof( IValidator<> ) ) )
					.WithService.Select( ( type, all ) =>
					{
						var contracts = type.GetInterfaces()
							.Where( i => i.IsAttributeDefined<ContractAttribute>() )
							.ToArray();
						return contracts;
					} )
					.LifestyleSingleton()
			);
        }
    }
}
